// Copyright 2009, Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.urchin.dataapi.rest.reportservice;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Iterator;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
 * This code sample
 *  - retrieves list of tables and supported dimensions and metrics for specified profile
 *  - retrieves list of dimensions and metrics for specified profile and [optional] table
 * 
 * To build and run the sample you need to download Apache Axis 1.4.1 from 
 * http://ws.apache.org/axis2/download/1_4_1/download.cgi
 * 
 * To generate the web services stubs you should run WSDL2Java from Axis bin directory: 
 * %AXIS2_HOME%/bin/wsdl2java.sh -uri http://server[:port]/services/v1/reportservice?wsdl -d adb -p com.google.urchin.dataapi.soap.reportservice -s -S .
 */

public class ReportService {
  // login information
  private static final String login = "URCHIN_LOGIN";
  private static final String password = "URCHIN_PASSWORD";
  private static final String serviceURL = "http://URCHINHOST:URCHINPORT/services/v1/adminservice/";
  
  // service arguments
  private static final int profileId = 1;
  private static String startDate = "2008-01-01";
  private static String endDate = "2009-01-01";

  public static void main(String[] args) { 
    try {
      GetTableList();
      GetDataWithImplicitTable();
      GetDataFiltered();
      GetDataSorted();
      GetDataAggregated();
    }
    catch(Exception e) {
      e.printStackTrace(); 
    }
  }

  /*
   * Retrieve list of tables and supported dimensions/metrics
   */
  public static void GetTableList() throws Exception {
    try {
      String url = serviceURL + "tables/?" + 
                   "login=" + login + "&" +
                   "password=" + password + "&" +
                   "profileId=" + profileId;
      URL service = new URL(url);
      // create the buffering character-input stream
      BufferedReader in = new BufferedReader(new InputStreamReader(service.openStream()));

      // create XPath for retrieving data
      XPathFactory fact = XPathFactory.newInstance();
      XPath xp = fact.newXPath();
      InputSource is = new InputSource(in);
      
      // set namespace context
      xp.setNamespaceContext(new UrchinNamespaceContext());

      // retrieve list of tables
      NodeList tables = (NodeList)xp.evaluate("/tns:getTableListResponse/table", is, XPathConstants.NODESET);

      // dump each record
      System.out.println("reportservice/tables/");
      System.out.println("url:" + url);
      for(int i = 0; i < tables.getLength(); i++){
        System.out.println("\ttable id: " + xp.evaluate("tableId/text()", tables.item(i)));

        // retrieve dimensions
        NodeList dimensions = (NodeList)xp.evaluate("dimensions/dimension/text()", tables.item(i), XPathConstants.NODESET);
        for(int j = 0; j < dimensions.getLength(); j++){
          System.out.println("\tdimension: " + dimensions.item(j).getNodeValue());
        }

        // retrieve list of metrics
        NodeList metrics = (NodeList)xp.evaluate("metrics/metric/text()", tables.item(i), XPathConstants.NODESET);
        for(int j = 0; j < metrics.getLength(); j++){
            System.out.println("\tmetric: " + metrics.item(j).getNodeValue());
        }
      }
      in.close();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Retrieve data with implicit table id for specific date range
   */
  private static void GetDataWithImplicitTable(){
    try {
      // compose REST URL
      String url = serviceURL + "data" + 
                   "?login=" + login + 
                   "&password=" + password + 
                   "&ids=" + profileId + 
                   "&start-date=" + startDate + 
                   "&end-date=" + endDate + 
                   "&dimensions=u:visitor_id" + 
                   "&metrics=u:pages,u:visits" + 
                   "&max-results=5";
      URL service = new URL(url);
      // create the buffering character-input stream
      BufferedReader in = new BufferedReader(new InputStreamReader(service.openStream()));
  
      System.out.println("reportservice/data");
      System.out.println("url:" + url);
  
      // create XPath for retrieving data
      XPathFactory fact = XPathFactory.newInstance();
      XPath xp = fact.newXPath();
      InputSource is = new InputSource(in);
      
      // set namespace context
      xp.setNamespaceContext(new UrchinNamespaceContext());
      // retrieve list of profiles
      NodeList records = (NodeList)xp.evaluate("/tns:getDataResponse/record", is, XPathConstants.NODESET);
      // dump each record
      for(int i = 0; i < records.getLength(); i++){
        System.out.println("record: ");
        
        //retrieve record id
        System.out.println("\trecord id: " + xp.evaluate("recordId/text()", records.item(i)));
        
        // retrieve dimensions
        NodeList dimensions = (NodeList)xp.evaluate("dimensions/dimension", records.item(i), XPathConstants.NODESET);
        for(int j = 0; j < dimensions.getLength(); j++){
          System.out.println("\tdimension: name: " + xp.evaluate("@name", dimensions.item(j)) + " value: " + xp.evaluate("text()", dimensions.item(j)));
        }
        
        // retrieve metrics
        NodeList metrics = (NodeList)xp.evaluate("metrics/*", records.item(i), XPathConstants.NODESET);
        for(int j = 0; j < metrics.getLength(); j++){
          System.out.println("\tmetric: name: " + metrics.item(j).getLocalName() + " value: " + xp.evaluate("text()", metrics.item(j)));
        }
      }
      in.close();
    }
    catch(Exception e) {
      e.printStackTrace(); 
    }
  }

  /**
   * Retrieve data from "1" table and apply filter
   */
  public static void GetDataFiltered() throws Exception {
    try {
      // compose REST URL
      String url = serviceURL + "data" + 
                   "?login=" + login + 
                   "&password=" + password + 
                   "&ids=" + profileId + 
                   "&start-date=" + startDate + 
                   "&end-date=" + endDate + 
                   "&dimensions=u:utm_source,u:utm_medium,u:utm_campaign" + 
                   "&metrics=u:pages,u:visits,u:transactions" +
                   "&filters=u:utm_source%3D~direct,u:pages%3E0" +
                   "&max-results=5";
      URL service = new URL(url);
      // create the buffering character-input stream
      BufferedReader in = new BufferedReader(new InputStreamReader(service.openStream()));
  
      System.out.println("reportservice/data");
      System.out.println("url:" + url);
  
      // create XPath for retrieving data
      XPathFactory fact = XPathFactory.newInstance();
      XPath xp = fact.newXPath();
      InputSource is = new InputSource(in);
  
      // set namespace context
      xp.setNamespaceContext(new UrchinNamespaceContext());
      // retrieve list of profiles
      NodeList records = (NodeList)xp.evaluate("/tns:getDataResponse/record", is, XPathConstants.NODESET);
      // dump each record
      for(int i = 0; i < records.getLength(); i++){
        System.out.println("record: ");
  
        //retrieve record id
        System.out.println("\trecord id: " + xp.evaluate("recordId/text()", records.item(i)));
  
        // retrieve dimensions
        NodeList dimensions = (NodeList)xp.evaluate("dimensions/dimension", records.item(i), XPathConstants.NODESET);
        for(int j = 0; j < dimensions.getLength(); j++){
          System.out.println("\tdimension: name: " + xp.evaluate("@name", dimensions.item(j)) + " value: " + xp.evaluate("text()", dimensions.item(j)));
        }
  
        // retrieve metrics
        NodeList metrics = (NodeList)xp.evaluate("metrics/*", records.item(i), XPathConstants.NODESET);
        for(int j = 0; j < metrics.getLength(); j++){
          System.out.println("\tmetric: name: " + metrics.item(j).getLocalName() + " value: " + xp.evaluate("text()", metrics.item(j)));
        }
      }
      in.close();
    }
    catch(Exception e) {
      e.printStackTrace(); 
    }
  }

  /**
   * Retrieve data from transactions table and apply sort
   */
  public static void GetDataSorted() throws Exception {
    try {
      // compose REST URL
      String url = serviceURL + "data" + 
                   "?login=" + login + 
                   "&password=" + password + 
                   "&ids=" + profileId + 
                   "&start-date=" + startDate + 
                   "&end-date=" + endDate + 
                   "&dimensions=u:transaction_id" + 
                   "&metrics=u:transactions,u:revenue" +
                   "&sort=-u:transactions" +
                   "&max-results=5";
      URL service = new URL(url);
      // create the buffering character-input stream
      BufferedReader in = new BufferedReader(new InputStreamReader(service.openStream()));
  
      System.out.println("reportservice/data");
      System.out.println("url:" + url);
  
      // create XPath for retrieving data
      XPathFactory fact = XPathFactory.newInstance();
      XPath xp = fact.newXPath();
      InputSource is = new InputSource(in);
  
      // set namespace context
      xp.setNamespaceContext(new UrchinNamespaceContext());
      // retrieve list of profiles
      NodeList records = (NodeList)xp.evaluate("/tns:getDataResponse/record", is, XPathConstants.NODESET);
      // dump each record
      for(int i = 0; i < records.getLength(); i++){
        System.out.println("record: ");

        //retrieve record id
        System.out.println("\trecord id: " + xp.evaluate("recordId/text()", records.item(i)));

        // retrieve dimensions
        NodeList dimensions = (NodeList)xp.evaluate("dimensions/dimension", records.item(i), XPathConstants.NODESET);
        for(int j = 0; j < dimensions.getLength(); j++){
          System.out.println("\tdimension: name: " + xp.evaluate("@name", dimensions.item(j)) + " value: " + xp.evaluate("text()", dimensions.item(j)));
        }

        // retrieve metrics
        NodeList metrics = (NodeList)xp.evaluate("metrics/*", records.item(i), XPathConstants.NODESET);
        for(int j = 0; j < metrics.getLength(); j++){
          System.out.println("\tmetric: name: " + metrics.item(j).getLocalName() + " value: " + xp.evaluate("text()", metrics.item(j)));
        }
      }
      in.close();
    }
    catch(Exception e) {
      e.printStackTrace(); 
    }
  }

  /**
   * Retrieves data from transactions table and applies sort
   */
  public static void GetDataAggregated() throws Exception {
    try {
      // compose REST URL
      String url = serviceURL + "data" + 
                   "?login=" + login + 
                   "&password=" + password + 
                   "&ids=" + profileId + 
                   "&start-date=" + startDate + 
                   "&end-date=" + endDate + 
                   "&dimensions=u:month" + 
                   "&metrics=u:hits,u:bytes" +
                   "&sort=u:hits" +
                   "&max-results=5";
      URL service = new URL(url);
      // create the buffering character-input stream
      BufferedReader in = new BufferedReader(new InputStreamReader(service.openStream()));
  
      System.out.println("reportservice/data");
      System.out.println("url:" + url);
  
      // create XPath for retrieving data
      XPathFactory fact = XPathFactory.newInstance();
      XPath xp = fact.newXPath();
      InputSource is = new InputSource(in);

      // set namespace context
      xp.setNamespaceContext(new UrchinNamespaceContext());
      // retrieve list of profiles
      NodeList records = (NodeList)xp.evaluate("/tns:getDataResponse/record", is, XPathConstants.NODESET);
      // dump each record
      for(int i = 0; i < records.getLength(); i++){
        System.out.println("record: ");
  
        //retrieve record id
        System.out.println("\trecord id: " + xp.evaluate("recordId/text()", records.item(i)));
  
        // retrieve dimensions
        NodeList dimensions = (NodeList)xp.evaluate("dimensions/dimension", records.item(i), XPathConstants.NODESET);
        for(int j = 0; j < dimensions.getLength(); j++){
          System.out.println("\tdimension: name: " + xp.evaluate("@name", dimensions.item(j)) + " value: " + xp.evaluate("text()", dimensions.item(j)));
        }
  
        // retrieve metrics
        NodeList metrics = (NodeList)xp.evaluate("metrics/*", records.item(i), XPathConstants.NODESET);
        for(int j = 0; j < metrics.getLength(); j++){
          System.out.println("\tmetric: name: " + metrics.item(j).getLocalName() + " value: " + xp.evaluate("text()", metrics.item(j)));
        }
      }
      in.close();
    }
    catch(Exception e) {
      e.printStackTrace(); 
    }
  }
}
/**
 * Urchin Data API namespace context implementation
 */
class UrchinNamespaceContext implements NamespaceContext {
  public String getNamespaceURI(String prefix) {
    if (prefix == null) throw new NullPointerException("Null prefix");

    if (prefix.equals("tns")) return "https://urchin.com/api/urchin/v1/";
    else if ("xml".equals(prefix)) return XMLConstants.XML_NS_URI;
    return XMLConstants.NULL_NS_URI;
  }

  public String getPrefix(String namespaceURI) {
    throw new UnsupportedOperationException();
  }

  public Iterator getPrefixes(String namespaceURI) {
    throw new UnsupportedOperationException();
  }
}
